张家村码头的粮食堆积如山,每天都需要用船运到镇里。
但是去镇上有50公里,只有水路可走。
一大早,码头工人们就开始干活了, 为了早点干完收工回家,一船接一船,拼命地发送粮食。
可是这水路不仅仅是张家村在运粮食,白头村还往外运石头, 东平村还往外运沙子,大家都拼命地往外发货物,再加上各式各样,络绎不绝的商船、客船, 大家很快就发现,船只太多,水面出现拥堵,工人们只好等待。
工人们想这也不是个事儿,大家围成一圈,蹲在码头上一边抽烟,一边商量对策。
水路很长,怎么判断水面是不是拥堵了呢?
新来的小张说道:“我有个办法,不要一下子发那么多船过去, 我们来个慢启动,首先运输一船粮食过去,船到镇上以后卸掉粮食马上返回,如果能在很短的时间内返回,说明水面交通状况还好,可以继续搬运粮食。
包工头老李说:“不错,这个船有检测水面拥堵状况的作用。然后呢?”
小张说: “接下来搬运2船粮食过去,如果依旧能够在预定的时间内返回,则继续搬运3船粮食,每次加一船, 依次类推。”
老王在码头上干了好几年, 他立刻跳了起来:“拉到吧你,这样太慢了!我提议,加快运输速度,每次发送的船只数量是上一次的两倍。”
也就是说,第一次发一条船,如果在预定时间内返回,第二次发2条船,然后是4条船,8条船!
老李说:“不行不行,每次都是之前的两倍,增长得太快了,大家如果都这么玩,水路很快就阻塞了。”
“我还没说完,” 老王补充, “为了防止拥塞,我们设置一个阈值(其实就是TCP中的ssthresh),当一次发船数量达到这个数,我们就降低速度,不要翻倍,每次只比上次多发一条船。”
老王一边说一边拿了一根木棍在地上画图:
(点击看大图)
我们把前面的阶段叫慢启动发船阶段,后面的阶段叫拥塞避免发船阶段。
大家对老王的方案纷纷叫好,就是它了!
只有小张慢悠悠地说:“随着每次发送船只的数量越来越多,水路早晚还是要阻塞的。”
“没事,”老王胸有成竹,“如果阻塞了,我们就回到最初的状态,从1条船,2条船,4条船......开始,但是,我们也要把阈值ssthresh调整一下,把它变小,嗯,假设上次阻塞时发船的数量是24, 那就把阈值调整为它的一半, 就是12。”
(点击看大图)
“不错,不错,当水路频繁阻塞时,这个阈值就会下降得很快,发到水面上的船也会大大减少。” 包工头老李总结,“我们要不按照这个方案试试?”
小张嘴里嘟囔着:“试试就试试,不过你得和白头村,东平村他们协调好,大家都得用这个方案才行,要不然我们就吃亏了。”
“那是自然!这事我来办!”老李满口答应。
故事结束了吗?其实没有,老王发明的其实叫做 TCP Tahoe算法。TCP的拥塞控制还有两个部分,即快速重传和快速恢复,这里再简单介绍一下。
快速重传比较简单,用一个图就可以表示:
在TCP中,数据都是有序号的,例如M1,M2,M3... 。
发送方发出了M1和M2, 接收方都收到了。
但是M3报文丢失了, 接收方没有收到,随后它收到了M4,M5,M6, 按照快速重传的算法,接收方重复确认M2,让发送方知道,M3没有收到。
当发送方收到3个对M2的重复确认的时候,它就意识到,坏菜了,M3丢了, 这时候不必继续等待M3设置的重传计时器到期,立刻重传M3。
统计表明,由于发送方尽早重传未被确认的报文段,可以使整个网络吞吐量提高约20%。
有了快速重传,可以改进下故事中的拥塞避免模型了。
(点击看大图)
当发送端收到三个重复确认的时候,就执行快速重传算法,并且把阈值减少。
但是这个时候它认为网络很可能没有发生阻塞, 不用执行慢启动算法,而是直接从新阈值开始,线性增大。
这个算法称为TCP Reno版,被很多TCP的实现所采用。